package istar.behaviour;

import istar.IElement;
import istar.IElementLink;
import istar.agent.IstarJadeAgent;
import istar.impl.AbstractBasicTask;
import istar.impl.Task;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.util.leap.Collection;

import java.util.Iterator;
import java.util.Random;
import java.util.Vector;

import log.Log;

public class MeansEndUniqueBehaviour extends SequentialBehaviour implements IistarBehaviour{

	private Behaviour subBehaviour=null;
	private Vector<IElement> means = new Vector<IElement>();
	private IElement endElement;
	private boolean log = true;
	private boolean error = false;
	//private List<Belief> believes;
	
	public MeansEndUniqueBehaviour(IstarJadeAgent _agent, IElement endElement){
		super(_agent);
		this.endElement = endElement;
		this.setBehaviourName(endElement.getName());
		//performBehaviour();
	}
	
	public MeansEndUniqueBehaviour(IElement endElement){
		super();
		this.endElement = endElement;
		this.setBehaviourName(endElement.getName());
		//performBehaviour();
	}
	
	
	
	
	@Override
	public void onStart() {
		try {
			super.onStart();
			performBehaviour();
		} catch (Exception e) {
			error = true;
			this.endElement.getMain().getContent().clear();
			this.endElement.getMain().getContent().add(e.getMessage());
			//System.out.println(" >>>>> "+e.getMessage());;
		}
	}
	
	@Override
	public int onEnd() {
		if (error){
			((IstarJadeAgent)myAgent).log("Ending " + this.getBehaviourName() + " with error");
			//System.out.println("Ending " + this.getBehaviourName() + " with error");
			return ERROR_STATE_CODE;
		}
		else
			return myOnEnd();
	}


	private void performBehaviour(){
		
		if (!this.getChildren().isEmpty()){
			Behaviour[] subs = new Behaviour[this.getChildren().size()];
			int i = 0;
			Iterator<Behaviour> itSubs = this.getChildren().iterator();
			while (itSubs.hasNext()){
				subs[i] = itSubs.next();
				i++;
			}
			for (int j=0;j<subs.length;j++){
				this.getChildren().remove(subs[j]);
			}
		}
		
		Vector<IElement> means = new Vector<IElement>();
		
		String subNames = "";		
		Iterator<IElement> itMeansEndLinks = endElement.getMeansEndLink().getTargetElements().iterator();
		while (itMeansEndLinks.hasNext()){
			IElement mean = itMeansEndLinks.next();
			means.add(mean);
			subNames += mean.getName() + ";";
		}
		Task theOne =null;
		Iterator<IElement> itMeans = means.iterator();
		while (itMeans.hasNext()){
			Task mean = (Task)itMeans.next();
			// workable?
			//if (mean.workable((IstarJadeAgent)myAgent)){
			if (theOne==null){
				theOne = mean;
			}
			else {
				// first criteria: contribution score
				if (mean.getContributionScore() > theOne.getContributionScore()){
					theOne = mean;
				}
				else {
					if (mean.getContributionScore() == theOne.getContributionScore()){
						// second criteria: believiability
						if ( mean.believiability((IstarJadeAgent)this.myAgent) >
							 theOne.believiability((IstarJadeAgent)this.myAgent)) {
							theOne = mean;
						}
						else if ( mean.believiability((IstarJadeAgent)this.myAgent) ==
						 theOne.believiability((IstarJadeAgent)this.myAgent)) {
							// third criteria: random choice
							Random r = new Random();
							if (r.nextBoolean())
								theOne = mean;
						}
					}
				}
			}
		}	
		
		if (theOne!=null){
			theOne.getContent().addAll(endElement.getContent());
			
			//theOne.setExecutionNumber(((AbstractElement)endElement).getExecutionNumber());
			
			// if subElemnt is internal
			if (theOne.getOwner()==endElement.getOwner()){
				if (theOne.isBasic()){
					subBehaviour = ((AbstractBasicTask)theOne).getBehaviour();
				}
				else if (theOne.getMyDecompositionLink().getType()==IElementLink.SEQUENTIAL){
					subBehaviour = new SequentialTaskBehaviour((IstarJadeAgent)this.myAgent, theOne);

				}
				else if (theOne.getMyDecompositionLink().getType()==IElementLink.PARALLEL){
					subBehaviour = new IstarParallelBehaviour((IstarJadeAgent)this.myAgent, theOne, ParallelBehaviour.WHEN_ALL);
				}
			}
			else {
				// send a request message
				subBehaviour = new RequestExternalElement((IstarJadeAgent)this.myAgent, theOne, endElement);
			}
			log(this.getBehaviourName() + " has: " + subNames);
			log("behaviour name="+ getBehaviourName() + " adding subBehaviour " + subBehaviour.getBehaviourName() ); 
			this.addSubBehaviour(subBehaviour);
		}
		else {
			System.out.println(" There is no mean workable! ");
		}
	}

	
	public int myOnEnd() {
		//log("<behaviour type=" + getClass().getName() + " name="+ getBehaviourName() + " ending />");
		/*
		if (endElement.achieved()){
			//System.out.println("["+ this.myAgent.getLocalName()+ "] "+ this.getBehaviourName()+ " returning 1" );
			return 1;
		}
		else {
			//System.out.println("["+ this.myAgent.getLocalName()+ "] "+ this.getBehaviourName()+ " returning 0" );
			return 1;
		}
		*/
		return subBehaviour.onEnd();

	}
	
	public void log(String _phrase){
		if (this.log){
			((IstarJadeAgent)myAgent).log( _phrase);
		}
	}

	@Override
	public String getExecutionNumber() {
		return this.endElement.getExecutionNumber();
	}

	
	
}
